
#if defined loader_inc
 #endscript
#endif
#define loader_inc

#tryinclude <a_samp>

#include <file>
#include <cstring>

//#include <ideparse>

#if defined ENABLE_LOD_SUPPORT
 #include <lod>
#endif

#if !defined CONST_STRLEN
 #define CONST_STRLEN(%0) (sizeof(%0)-1)
#endif

#if !defined LOADER_OBJECT
 #tryinclude <a_objects>
 #if defined ENABLE_LOD_SUPPORT
  #define LOADER_OBJECT(%0,%1,%2,%3,%4,%5,%6,%7)	\
	CreateObject(%0,%1,%2,%3,%4,%5,%6)
 #else
  #define LOADER_OBJECT(%0,%1,%2,%3,%4,%5,%6)	CreateObject(%0,%1,%2,%3,%4,%5,%6)
 #endif
#endif

#if !defined LOADER_VEHICLE
 #define LOADER_VEHICLE	AddStaticVehicleEx
#endif

/*
#if !defined LOADER_VEHICLE_RCOL
 #define LOADER_VEHICLE_RCOL empty_
#endif*/

#if !defined LOADER_VCC
 #define LOADER_VCC	400
#endif

#if !defined LOADER_ENTRACE
 #define LOADER_ENTRACE	empty_
#endif

#if !defined LOADER_PICKUP
 #define LOADER_PICKUP	CreatePickup
#endif

#if !defined LOADER_CLASS
 #define LOADER_CLASS	AddPlayerClass
#endif

#if !defined LOADER_ICON
 #define LOADER_ICON	SetPlayerMapIcon
#endif


#define LOADER_TYPE_NON	0
#define LOADER_TYPE_LNK 1
#define LOADER_TYPE_ENT 2
#define LOADER_TYPE_RAW 3
#define LOADER_TYPE_MAP 4
#define LOADER_TYPE_IPL 5
#define LOADER_TYPE_CLS 6
#define LOADER_TYPE_PCK 7
#define LOADER_TYPE_CYV 8
#define LOADER_TYPE_MTA 9

static stock empty_({Float,_}:...) { return 1; }


static stock token_by_delim(const string[], return_str[], delim, start_index)
{
	new x=0;
	if(start_index < 0) return(-1);
	while(string[start_index] == ' ' || string[start_index] == '\t')
		start_index++;
	while(string[start_index] != EOS && string[start_index] != delim && string[start_index] != '#')
	{
		return_str[x] = string[start_index];
		x++;
		start_index++;
	}
	return_str[x] = EOS;
	if(string[start_index] == EOS) start_index = (-1);
	return start_index;
}

/*
static checkline(const line[])
{
	// skip lines starting with # or // or EOL
	if(line[0] == '#' || line[0] == '\n' || line[0] == '\r') return false;
	return true;
}*/
#define checkline(%1) (!(%1[0] == '#' || %1[0] == '\n' || %1[0] == '\r'))

#define CHECK_FILE(%1) 	if(!%1) { printf("Unable to read file %s", filename); return 0; }

#define CHECK_LINE(%1) if(!checkline(%1)) continue

stock Load_MAP(const filename[])
{
	new File:file_ptr;
	new line[256];
	new var_from_line[64];

	//new modelname[64];
	//new interior;
	//new flags;

	new modelid;
	new Float:sx;
	new Float:sy;
	new Float:sz;
	new Float:rx;
	new Float:ry;
	new Float:rz;


	new index;
	new objs_loaded;

	file_ptr = fopen(filename,filemode:io_read);
	CHECK_FILE(file_ptr)

	objs_loaded = 0;

	while(fread(file_ptr,line,sizeof(line)) > 0)
	{

		CHECK_LINE(line);

		index = 0;

		// model id
		index = token_by_delim(line,var_from_line,',',index);
		if(index == (-1)) continue;
		modelid = strval(var_from_line);
		if(modelid < 1) continue;

		// Read X, Y, Z, Rotation
		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		sx = floatstr(var_from_line);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		sy = floatstr(var_from_line);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		sz = floatstr(var_from_line);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		//if(var_from_line[0] == ' ')
		//	format(var_from_line, sizeof(var_from_line), "%s", var_from_line[1]);
		rx = floatstr(var_from_line[0]);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
 		//if(var_from_line[0] == ' ')
		//	format(var_from_line, sizeof(var_from_line), "%s", var_from_line[1]);
 		ry = floatstr(var_from_line[0]);

		index = token_by_delim(line,var_from_line,';',index+1);
		if(index == (-1)) continue;
		//if(var_from_line[0] == ' ')
		//	format(var_from_line, sizeof(var_from_line), "%s", var_from_line[1]);
 		rz = floatstr(var_from_line);

		// create object
		#if defined IPL_DEBUG
		printf("CreateObject(%d, %f, %f, %f,%f, %f, %f); ", modelid, sx, sy, sz, rx, ry, rz);//, modelname, interior, flags);
		#endif

		#if defined objects_inc
		if(!IsValidObjectModel(modelid))
			printf("Warning(%d): bad object model (%d)", objs_loaded, modelid);
		#endif

		#if defined ENABLE_LOD_SUPPORT
		new lod = FindLODObject(modelid);

		#if defined objects_inc
		if(lod != modelid && !IsValidObjectModel(lod))
			printf("Warning(%d): bad  LOD object model (%d)", objs_loaded, lod);
		#endif

		if(LOADER_OBJECT(modelid, sx, sy, sz, rx, ry, rz, //FindLODModel("data/maps/list.lst", modelid));
			lod) < 0)
		{
			printf("Error(%d): cannot load more objects", objs_loaded);
			fclose(file_ptr);
			return objs_loaded;
		}
		#else
		if(LOADER_OBJECT(modelid, sx, sy, sz, rx, ry, rz) < 0)
		{
			printf("Error(%d): cannot load more objects", objs_loaded);
			fclose(file_ptr);
			return objs_loaded;
		}
		#endif

		//CreateObject(modelid, sx, sy, sz, deg1, deg2, deg3);

		objs_loaded++;
	}

	fclose(file_ptr);
	printf("Loaded %d objects from %s", objs_loaded, filename);
	return objs_loaded;
}

stock Load_IPL(const filename[])
{
	new File:file_ptr;
	new line[256];
	new var_from_line[64];

	//new modelname[64];
	//new interior;
	//new flags;
/*
	#define MAX_MODEL_BUF 60
	new idxmodelid[MAX_MODEL_BUF];
*/
	new modelid;
	new Float:sx;
	new Float:sy;
	new Float:sz;
	new Float:rx;
	new Float:ry;
	new Float:rz;
	new Float:rw;


/*	new flag;
	new inst_idx;
*/
	//new Float:deg1, Float:deg2, Float:deg3;

	new index;
	new objs_loaded;
	new bool:isloading = false;

	file_ptr = fopen(filename,filemode:io_read);
	CHECK_FILE(file_ptr)
	objs_loaded = 0;

	while(fread(file_ptr,line,sizeof(line)) > 0)
	{
		CHECK_LINE(line);


		if(!strcmp(line, "inst", true, 4))
		{
			isloading = true;
/*			inst_idx = 0;
*/			continue;
		}
		else if(!strcmp(line, "end", true, 3)&&isloading)
		{
			isloading = false;
/*			for(new i = 0; i < inst_idx; i++)
				idxmodelid[i] = 0;
*/			continue;
		}
		else if(!isloading)
			continue;

	// model id
		index = token_by_delim(line,var_from_line,',', 0);
		if(index == (-1)) continue;
 		modelid = strval(var_from_line);
 		if(modelid < 1) continue;

		// model name - skip
		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		// interior - skip
		index = token_by_delim(line,var_from_line,',',index+1);
 		if(index == (-1)) continue;
		//interior = strval(var_from_line);

		// Read X, Y, Z, Rotation
		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		sx = floatstr(var_from_line);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		sy = floatstr(var_from_line);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		sz = floatstr(var_from_line);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		#if defined IPL_DEBUG
		//print(var_from_line);
		#endif
		//if(var_from_line[0] == ' ')
		//	format(var_from_line, sizeof(var_from_line), "%s", var_from_line[1]);
		rx = floatstr(var_from_line[0]);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		#if defined IPL_DEBUG
		//print(var_from_line);
		#endif
 		//if(var_from_line[0] == ' ')
		//	format(var_from_line, sizeof(var_from_line), "%s", var_from_line[1]);
 		ry = floatstr(var_from_line[0]);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		#if defined IPL_DEBUG
		//print(var_from_line);
		#endif
		//if(var_from_line[0] == ' ')
		//	format(var_from_line, sizeof(var_from_line), "%s", var_from_line[1]);
 		rz = floatstr(var_from_line);

		index = token_by_delim(line,var_from_line,',',index+1);
		#if defined IPL_DEBUG
		//print(var_from_line);
		#endif
		//if(var_from_line[0] == ' ')
		//	format(var_from_line, sizeof(var_from_line), "%s", var_from_line[1]);
		if(index == (-1)) continue;
		rw = floatstr(var_from_line[0]);

		// flags - skip
/*		index = token_by_delim(line,var_from_line,',',index+1);
		//if(index == (-1)) continue;
		flag = strval(var_from_line);
		#if defined IPL_DEBUG
		printf("%s: %d", var_from_line, flag);
		#endif
*/
		#if defined IPL_DEBUG
		printf("%0.16f/%0.16f/%0.16f/%0.16f", rx, ry, rz, rw);
		#endif
		// create object
		TransformAngle(-rx, -ry, -rz, rw, rx, ry, rz);
		#if defined IPL_DEBUG
		printf("CreateObject(%d, %f, %f, %f,%f, %f, %f); ", modelid, sx, sy, sz, rx, ry, rz);//, modelname, interior, flags);
		#endif

/*		if(flag > 0 && flag < MAX_MODEL_BUF && idxmodelid[flag])
		{
			LOADER_OBJECT(modelid, sx, sy, sz, rx, ry, rz, idxmodelid[flag]);
			#if defined IPL_DEBUG
			printf("modelid %d: flag %d, lod: %d", modelid, flag, idxmodelid[flag]);
			#endif
		}
		else
*/
		#if defined objects_inc
		if(!IsValidObjectModel(modelid))
			printf("Warning(%d): bad object model (%d)", objs_loaded, modelid);
		#endif


		#if defined ENABLE_LOD_SUPPORT
		new lod = FindLODObject(modelid);

		#if defined objects_inc
		if(lod != modelid && !IsValidObjectModel(lod))
			printf("Warning(%d): bad  LOD object model (%d)", objs_loaded, lod);
		#endif


		if(LOADER_OBJECT(modelid, sx, sy, sz, rx, ry, rz, lod) < 0)
		{
			printf("Error(%d): cannot load more objects", objs_loaded);
			fclose(file_ptr);
			return objs_loaded;
		}
		#else
		if(LOADER_OBJECT(modelid, sx, sy, sz, rx, ry, rz) < 0)
		{
			printf("Error(%d): cannot load more objects", objs_loaded);

			fclose(file_ptr);
			return objs_loaded;
		}
		#endif
		//CreateObject(modelid, sx, sy, sz, deg1, deg2, deg3);

		objs_loaded++;

		// store modelid
/*		if(inst_idx < MAX_MODEL_BUF)
		{
			idxmodelid[inst_idx] = modelid;
			inst_idx++;
		}
*/	}

	fclose(file_ptr);
	printf("Loaded %d objects from %s", objs_loaded, filename);
	return objs_loaded;
}

/*
stock TransformAngle(Float:qx, Float:qy, Float:qz, Float:qw, &Float:x, &Float:y, &Float:z)
{
	//new Float:qw2 = qw*qw;
	new Float:qx2 = qx*qx;
	new Float:qy2 = qy*qy;
	new Float:qz2 = qz*qz;
	new Float:test= qx*qy + qz*qw;
	if (test > 0.4999999999999) {
		y = -2*atan2(qx,qw);
		z = -90;
		x = 0;
		#if defined IPL_DEBUG
		printf("%f, %f %f %f", test, x, y ,z);
		#endif
		return;
	}
	if (test < -0.49999999999) {
		y = 2*atan2(qx,qw);
		z = 90;
		x = 0;
		#if defined IPL_DEBUG
		printf("%f, %f %f %f", test, x, y ,z);
		#endif
		return;
	}
	new Float:h = atan2(2*qy*qw-2*qx*qz,1-2*qy2-2*qz2);
	new Float:a = asin(2*qx*qy+2*qz*qw);
	new Float:b = atan2(2*qx*qw-2*qy*qz,1-2*qx2-2*qz2);
	y = anglef(-h);//180/PI;
	z = anglef(-a);//180/PI;
	x = anglef(-b);//180/PI;

}*/

static stock TransformAngle(Float:qx, Float:qy, Float:qz, Float:qw, &Float:x, &Float:y, &Float:z)
{
	new Float:sqw = qw*qw;
	new Float:sqx = qx*qx;
	new Float:sqy = qy*qy;
	new Float:sqz = qz*qz;

	new Float:vx = atan2(2.0 * (qx*qy + qz*qw), sqx - sqy - sqz + sqw);
	new Float:vy = asin(-2.0 * (qx*qz - qy*qw));
	new Float:vz = atan2(2.0 * (qy*qz + qx*qw), -sqx - sqy + sqz + sqw);

	x = vz;
	y = vy;
	z = vx;
	return;
}
/*
stock TransformAngle(Float:rX,Float:rY,Float:rZ,Float:rW,&Float:RX,&Float:RY,&Float:RZ)
{
	new Float:sqx = rX^2,Float:sqy = rY^2,
		Float:sqz = rZ^2,Float:sqw = rW^2,
		Float:unit = sqx + sqy + sqz + sqw,
		Float:test = rX*rY+rZ*rW;
	if(test > 0.4999999999999 * unit)
	{
		RX = 2 * atan2(rX,rW);
		RZ = PI/2;
		RY = 0;
	}
	else if(test < -0.4999999999999 * unit)
	{
		RX = -2 * atan2(rX,rW);
		RZ = -PI/2;
		RY = 0;
	}
	else
	{
		new Float:tmp = (2*rY*rW)-(2*rX*rZ);
		RX = atan2(tmp,sqx-sqy-sqz+sqw);
		RZ = asin(2 * test/unit);
		tmp = (2*rX*rW)-(2*rY*rZ);
		RY = atan2(tmp,-sqx+sqy-sqy+sqw);
	}
	RX = float(floatround(RX));
	RY = float(floatround(RY));
	RZ = float(floatround(RZ));
}
*/
/*
stock TransformAngle(Float:qx, Float:qy, Float:qz, Float:qw, &Float:x, &Float:y, &Float:z)
{
	if(qw > 1) qw=1; // if w>1 acos and sqrt will produce errors, this cant happen if quaternion is normalised
	//new Float:angle = 2 * acos(qw);
	new Float:s = floatsqroot(1-qw*qw); // assuming quaternion normalised then w is less than 1, so term always positive.
	if (s < 0.001)
	{
		// test to avoid divide by zero, s is always positive due to sqrt
		// if s close to zero then direction of axis not important
		x = qx; // if it is important that axis is normalised then replace with x=1; y=z=0;
		y = qy;
		z = qz;
	}
	else
	{
		x = qx / s; // normalise axis
		y = qy / s;
		z = qz / s;
	}
}*/

stock Load_RAW(const filename[])
{
	new File:file_ptr;
	new line[256];
	new var_from_line[64];
	new modelid;
	new Float:x;
	new Float:y;
	new Float:z;
	new Float:a;
	new c[2];
	new index;
	new vehicles_loaded;

	file_ptr = fopen(filename,filemode:io_read);
	CHECK_FILE(file_ptr)
	vehicles_loaded = 0;

	while(fread(file_ptr, line, sizeof(line)) > 0)
	{
		CHECK_LINE(line);

		index = 0;

	// Read type
		index = token_by_delim(line, var_from_line, ',' ,index);
		if(index == (-1)) continue;

		if(strcmp(var_from_line, "vcc", true) == 0)
			modelid = LOADER_VCC;
		else
			modelid = strval(var_from_line);
 		if(modelid < 400 || modelid > 612) continue;

		// Read X, Y, Z, Rotation
		index = token_by_delim(line, var_from_line,',', index+1);
		if(index == (-1)) continue;
		x = floatstr(var_from_line);

		index = token_by_delim(line, var_from_line,',', index+1);
		if(index == (-1)) continue;
		y = floatstr(var_from_line);

		index = token_by_delim(line, var_from_line,',', index+1);
		if(index == (-1)) continue;
		z = floatstr(var_from_line);

		index = token_by_delim(line, var_from_line,',',index+1);
		if(index == (-1)) continue;
		a = floatstr(var_from_line);

		// Read Color1, Color2
		index = token_by_delim(line, var_from_line,',',index+1);
		if(index == (-1)) continue;
		c[0] = strval(var_from_line);

		/*
		if(c[0] == -1)
			c[0] = LOADER_VEHICLE_RCOL1;

		index = token_by_delim(line, var_from_line,';',index+1);
		c[1] = strval(var_from_line);
		if(c[1] == -1)
			c[1] = LOADER_VEHICLE_RCOL2;

		*/

		#if defined LOADER_VEHICLE_RCOL
		if((c[0] == -1 || c[1] == -1) && modelid < 612)
			LOADER_VEHICLE_RCOL(modelid, c[0], c[1]);
		#endif
		//printf("%d|%f|%f|%f|%f|%d|%d",vehicletype,
		//SpawnX,SpawnY,SpawnZ,SpawnRot,Color1,Color2);

		LOADER_VEHICLE(modelid, x, y, z, a, c[0], c[1], -1);

		vehicles_loaded++;
	}

	fclose(file_ptr);
	printf("Loaded %d vehicles from %s",vehicles_loaded,filename);
	return vehicles_loaded;
}
/*
stock Load_CYCV(const filename[])
{
	new File:file_ptr;
	new line[256];
	new var_from_line[64];
	new modelid, modelvcc;

	//new Float:tmp[2],
	//	tmp2[2];

	new Float:x[3];
	new Float:y[3];
	new Float:z;
	new Float:a;
	new c[2];
	new i, j;

	new cyctype;
	#define CYCLE_TYPE_XY_OFFSET 1
	#define CYCLE_TYPE_IJ_OFFSET 2

	#define CYCLE_TYPE_NONGRID 4

	new index;
	new vehicles_loaded;


	file_ptr = fopen(filename,filemode:io_read);
	CHECK_FILE(file_ptr)
	vehicles_loaded = 0;

	while(fread(file_ptr, line, sizeof(line)) > 0)
	{
		CHECK_LINE(line);

		index = 0;

		// Read type
		index = token_by_delim(line, var_from_line, ',' ,index);
		if(index == (-1)) continue;

		if(strcmp(var_from_line, "vcc", true) == 0)
			modelid = -1;
		else
			modelid = strval(var_from_line);
 		if((modelid < 400 || modelid > 612) && modelid != -1) continue;

		index = token_by_delim(line, var_from_line,',', index+1);
		if(index == (-1)) continue;
		cyctype = strval(var_from_line);

		// Read X, Y, Z, Rotation
		index = token_by_delim(line, var_from_line,':', index+1);
		if(index == (-1)) continue;
		x[0] = floatstr(var_from_line);

		index = token_by_delim(line, var_from_line,':', index+1);
		if(index == (-1)) continue;
		if(cyctype == CYCLE_TYPE_XY_OFFSET)
			x[1] = floatstr(var_from_line);
		else if(cyctype == CYCLE_TYPE_IJ_OFFSET)
			i = strval(var_from_line);

		index = token_by_delim(line, var_from_line,',', index+1);
		if(index == (-1)) continue;
		x[2] = floatstr(var_from_line);

		index = token_by_delim(line, var_from_line,':', index+1);
		if(index == (-1)) continue;
		y[0] = floatstr(var_from_line);

		index = token_by_delim(line, var_from_line,':', index+1);
		if(index == (-1)) continue;
		if(cyctype == CYCLE_TYPE_XY_OFFSET)
			y[1] = floatstr(var_from_line);
		else if(cyctype == CYCLE_TYPE_IJ_OFFSET)
			j = strval(var_from_line);

		index = token_by_delim(line, var_from_line,',', index+1);
		if(index == (-1)) continue;
		y[2] = floatstr(var_from_line);

		index = token_by_delim(line, var_from_line,',', index+1);
		if(index == (-1)) continue;
		z = floatstr(var_from_line);

		index = token_by_delim(line, var_from_line,',',index+1);
		if(index == (-1)) continue;
		a = floatstr(var_from_line);

		// Read Color1, Color2
		index = token_by_delim(line, var_from_line,',',index+1);
		if(index == (-1)) continue;
		c[0] = strval(var_from_line);

		index = token_by_delim(line, var_from_line,';',index+1);
		c[1] = strval(var_from_line);

		//printf("%d|%f|%f|%f|%f|%d|%d",vehicletype,
		//SpawnX,SpawnY,SpawnZ,SpawnRot,Color1,Color2);


		if(cyctype == CYCLE_TYPE_XY_OFFSET) // xmin -> xmax or/and ymin -> ymax
		{
			if(x[1] != 0.0 && y[1] == 0.0) // line cycle, by x
			{
				for( ; x[0] < x[1]; x[0] += x[2], y[0] += y[2])
				{

					modelvcc = (modelid == -1)?LOADER_VCC:modelid;

					#if defined LOADER_VEHICLE_RCOL
					if(c[0] == -1 || c[1] == -1)
						LOADER_VEHICLE_RCOL(modelvcc, c[0], c[1]);
					#endif

					LOADER_VEHICLE(modelvcc, x[0], y[0], z, a, c[0], c[1], -1);
					//	(c[0] == -1)?LOADER_VEHICLE_RCOL1:c[0], (c[1] == -1)?LOADER_VEHICLE_RCOL2:c[1], -1);

					vehicles_loaded++;
				}
			}
			else if(x[1] == 0.0 && y[1] != 0.0) // line cycle, by y
			{
				for( ; y[0] < y[1]; x[0] += x[2], y[0] += y[2])
				{

					modelvcc = (modelid == -1)?LOADER_VCC:modelid;

					#if defined LOADER_VEHICLE_RCOL
					if(c[0] == -1 || c[1] == -1)
						LOADER_VEHICLE_RCOL(modelvcc, c[0], c[1]);
					#endif

					LOADER_VEHICLE(modelvcc, x[0], y[0], z, a, c[0], c[1], -1);

					vehicles_loaded++;
				}
			}
			else if(x[1] != 0.0 && y[1] != 0.0) // 2D grid cycle
			{
				for( ; x[0] < x[1]; x[0] += x[2])
				{
					for(new Float:tmp = y[0]; tmp < y[1]; tmp += y[2])
					{

						modelvcc = (modelid == -1)?LOADER_VCC:modelid;

						#if defined LOADER_VEHICLE_RCOL
						if(c[0] == -1 || c[1] == -1)
							LOADER_VEHICLE_RCOL(modelvcc, c[0], c[1]);
						#endif

						LOADER_VEHICLE(modelvcc, x[0], tmp, z, a, c[0], c[1], -1);

						vehicles_loaded++;
					}
				}
			}
		}
		else if(cyctype == CYCLE_TYPE_IJ_OFFSET) // 0 -> i or/and 0 -> j
		{
			if(!i && j) // line cycle, by j
			{
				for(new ti = 0; ti < j; x[0] += x[2], y[0] += y[2], ti++)
				{
					modelvcc = (modelid == -1)?LOADER_VCC:modelid;

					#if defined LOADER_VEHICLE_RCOL
					if(c[0] == -1 || c[1] == -1)
						LOADER_VEHICLE_RCOL(modelvcc, c[0], c[1]);
					#endif

					LOADER_VEHICLE(modelvcc, x[0], y[0], z, a, c[0], c[1], -1);

					vehicles_loaded++;
				}
			}
			else if(i && !j) // line cycle, by i
			{
				for(new ti = 0; ti < i; x[0] += x[2], y[0] += y[2], ti++)
				{

					modelvcc = (modelid == -1)?LOADER_VCC:modelid;
					#if defined LOADER_VEHICLE_RCOL
					if(c[0] == -1 || c[1] == -1)
						LOADER_VEHICLE_RCOL(modelvcc, c[0], c[1]);
					#endif

					LOADER_VEHICLE(modelvcc, x[0], y[0], z, a, c[0], c[1], -1);

					vehicles_loaded++;
					//print("in loop");
				}
			}
			else if(i && j) // 2D grid cycle
			{
				for(new ti = 0; ti < i; x[0] += x[2], ti++)
				{
					for(new tj = 0, Float:tmp = y[0]; tj < j; tmp += y[2], tj++)
					{

						modelvcc = (modelid == -1)?LOADER_VCC:modelid;
						#if defined LOADER_VEHICLE_RCOL
						if(c[0] == -1 || c[1] == -1)
							LOADER_VEHICLE_RCOL(modelvcc, c[0], c[1]);
						#endif
						LOADER_VEHICLE(modelvcc, x[0], tmp, z, a, c[0], c[1], -1);

						vehicles_loaded++;
					}
				}
			}
		}


		// next line
	}

	fclose(file_ptr);
	printf("Loaded %d vehicles from %s",vehicles_loaded,filename);
	return vehicles_loaded;
}
*/


stock Load_LNK(const filename[])
{
	new File:file_ptr;
	new line[256];
	new loadtype[64], loader;
	new path[96];
	new index;
	new tmp = strrchr(filename, '/');

	file_ptr = fopen(filename,filemode:io_read);
	CHECK_FILE(file_ptr)
	while(fread(file_ptr,line, sizeof(line)) > 0)
	{
		CHECK_LINE(line);

		//loader = LOADER_TYPE_NON;
		index = 0;

	// Read type
		index = token_by_delim(line,loadtype, ':',index);
		if(index == (-1)) continue;

		// read file path
		index = token_by_delim(line,path, ';', index+1);


		if(strcmp(loadtype, "link", true) == 0)
			loader = LOADER_TYPE_LNK;
		else if(strcmp(loadtype, "ipl", true) == 0)
			loader = LOADER_TYPE_IPL;
		else if(strcmp(loadtype, "rwmap", true) == 0)
			loader = LOADER_TYPE_MAP;
		else if(strcmp(loadtype, "rwent", true) == 0)
			loader = LOADER_TYPE_ENT;
		else if(strcmp(loadtype, "rwveh", true) == 0)
			loader = LOADER_TYPE_RAW;
		else if(strcmp(loadtype, "rwcls", true) == 0)
			loader = LOADER_TYPE_CLS;
		else if(strcmp(loadtype, "rwpck", true) == 0)
			loader = LOADER_TYPE_PCK;
		//else if(strcmp(loadtype, "cyveh", true) == 0)
		//	loader = LOADER_TYPE_CYV;
		else if(strcmp(loadtype, "mta", true) == 0)
			loader = LOADER_TYPE_MTA;
		else
			continue;


		if(tmp != -1)
		{
			strmid(loadtype, filename, 0, tmp);
			format(path, sizeof(path), "%s/%s", loadtype, path);
			//printf("%d:%s:%s", tmp, loadtype, path);
		}

		switch(loader)
		{
			case LOADER_TYPE_LNK: Load_LNK(path);
			case LOADER_TYPE_IPL: Load_IPL(path);
			case LOADER_TYPE_MAP: Load_MAP(path);
			case LOADER_TYPE_ENT: Load_ENT(path);
			case LOADER_TYPE_RAW: Load_RAW(path);
			case LOADER_TYPE_PCK: Load_PICKUP(path);
			//case LOADER_TYPE_CYV: Load_CYCV(path);
			case LOADER_TYPE_CLS: Load_Special_CLASS(path);
			case LOADER_TYPE_MTA: Load_MTA(path);
		}

	}

	fclose(file_ptr);
	return 1;
}

stock Load_ENT(const filename[])
{
	new File:file_ptr;
	new line[256];
	new var_from_line[64];

	new Float:p1[4];
	new Float:p2[4];
	new i1, i2, vw;

	new index;
	new enters_loaded;

	file_ptr = fopen(filename,filemode:io_read);
	CHECK_FILE(file_ptr)
	enters_loaded = 0;

	while(fread(file_ptr,line,256) > 0)
	{
		CHECK_LINE(line);

		index = 0;

		for(new i=0; i<4; i++)
		{
			index = token_by_delim(line,var_from_line,',',i==0?index:(index+1));
			if(index == (-1)) continue;

			p1[i] = floatstr(var_from_line);
		}

		for(new i=0; i<4; i++)
		{
			index = token_by_delim(line,var_from_line,',',index+1);
			if(index == (-1)) continue;

			p2[i] = floatstr(var_from_line);
		}

		// Read i1, i2
		index = token_by_delim(line,var_from_line,',',index+1);
		if(index != (-1))
			i1 = strval(var_from_line);
		else
			i1 = 0;

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index != (-1))
			i2 = strval(var_from_line);
		else
			i2 = 0;

		index = token_by_delim(line,var_from_line,';',index+1);
		if(index != (-1))
			vw = strval(var_from_line);
		else
			vw = 0;

		//printf("%d|%f|%f|%f|%f|%d|%d",vehicletype,
		//SpawnX,SpawnY,SpawnZ,SpawnRot,Color1,Color2);

		LOADER_ENTRACE(p1[0], p1[1], p1[2], p1[3], p2[0], p2[1], p2[2], p2[3], i1, i2, vw);

		enters_loaded++;
	}

	fclose(file_ptr);
	printf("Loaded %d enters from %s",enters_loaded,filename);
	return enters_loaded;
}

stock Load_PICKUP(const filename[])
{
	new File:file_ptr;
	new line[256];
	new var_from_line[64];

	new modelid,
		type;
	new Float:p[3];
	new vw;

	new index;
	new pcks_loaded;

	file_ptr = fopen(filename,filemode:io_read);
	CHECK_FILE(file_ptr)
	pcks_loaded = 0;

	while(fread(file_ptr,line,sizeof(line)) > 0)
	{
		CHECK_LINE(line);

		index = 0;

		index = token_by_delim(line,var_from_line,',',index);
		if(index == (-1)) continue;
		modelid = strval(var_from_line);
		if(modelid < 1) continue;

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		type = strval(var_from_line);
		if(type < 0) continue;


		for(new i=0; i<3; i++)
		{
			index = token_by_delim(line,var_from_line,',',index+1);
			if(index == (-1))
				break;

			p[i] = floatstr(var_from_line);
		}
		//if(index == -1) continue;

		index = token_by_delim(line,var_from_line,';',index+1);
		if(index == (-1))
			vw = 0;
		else
			vw = strval(var_from_line);

		LOADER_PICKUP(modelid, type, p[0], p[1], p[2], vw);

		pcks_loaded++;
	}

	fclose(file_ptr);
	printf("Loaded %d pickups from %s",pcks_loaded,filename);
	return pcks_loaded;
}

stock Load_MTA(const filename[])
{
	new File:file_ptr;
	new line[256];
	new var_from_line[64];

	new modelid;
	new obj_type;
	new Float:pos[3],
		Float:rot[3];

	new index;
	new objs_loaded;


	new const str_pos[][] =
	{
		"posX",
		"posY",
		"posZ"
	};

	new const str_rot[][] =
	{
		"rotX",
		"rotY",
		"rotZ"
	};


	file_ptr = fopen(filename,filemode:io_read);
	CHECK_FILE(file_ptr)
	objs_loaded = 0;


	while(fread(file_ptr,line,sizeof(line)) > 0)
	{
		CHECK_LINE(line);

		index = strchr(line, '<') + 1; // tag index
		if(!index) continue;

		index = token_by_delim(line, var_from_line, ' ', index);
		if(index == -1) continue; // tag with no params

		if(strcmp(var_from_line, "object", true) == 0)
			obj_type = LOADER_TYPE_MAP;
		else if(strcmp(var_from_line, "pickup", true) == 0)
			obj_type = LOADER_TYPE_PCK;
		else if(strcmp(var_from_line, "vehicle", true) == 0)
			obj_type = LOADER_TYPE_RAW;
		else // unknown object type
			continue;

		index = strfind(line, (obj_type == LOADER_TYPE_PCK)?("type"):("model"), true, index);
		if(index == -1) continue; // cannot find argument
		else index += ((obj_type == LOADER_TYPE_PCK)?4:5) + 2; /* =" */

		index = token_by_delim(line, var_from_line, '\"', index);
		if(index == -1) continue; // not a value

		modelid = strval(var_from_line);
		if(modelid < 1) continue; // modelid cannot be below 1

		if(obj_type == LOADER_TYPE_PCK) // proccess pickup type
		{
			if(strcmp(var_from_line, "health", true) == 0)
				modelid = (1240);
			else if(strcmp(var_from_line, "health", true) == 0)
				modelid = 1242;
			else if(strcmp(var_from_line, "money", true) == 0)
				modelid = 1211;
			else // weapon id -> object model id
			{
				if(modelid>=2&&modelid<=8)
					modelid = modelid+331;
				else if(modelid==1) modelid = 331;
				else if(modelid==9) modelid = 341;
				else if(modelid>=16&&modelid<=18)
					modelid = modelid + 342 - 16;
				else if((modelid>=22&&modelid<=29)||(modelid>=33&&modelid<=45))
					modelid = modelid + 324;
				else if(modelid==46) modelid = 371;
				else if(modelid==32) modelid = 372;
				else if(modelid==30||modelid==31)
					modelid = modelid + 325;
				else if(modelid>=10&&modelid<=15)
					modelid = modelid + 311;
				//else modelid = modelid;
			}
		}
		//

		for(new i = 0; i < 3; i++)
		{ // position
			index = strfind(line, str_pos[i], true, index);
			if(index == -1) break; // cannot find argument
			else index += 4 + 2;//CONST_STRLEN("=\""); /* =" */

			index = token_by_delim(line, var_from_line, '\"', index);
			if(index == -1) break; // not a value

			pos[i] = floatstr(var_from_line);
		}
		if(index == -1) continue;

		if(obj_type == LOADER_TYPE_MAP)
		{
			for(new i = 0; i < 2; i++)
			{ // x, y rotation
				index = strfind(line, str_rot[i], true, index);
				if(index == -1) break; // cannot find argument
				else index += 4 + 2;//CONST_STRLEN("=\""); /* =" */

				index = token_by_delim(line, var_from_line, '\"', index);
				if(index == -1) break; // not a value

				rot[i] = floatstr(var_from_line);
			}
			if(index == -1) continue;
		}
		if(obj_type == LOADER_TYPE_MAP || obj_type == LOADER_TYPE_RAW)
		{ // z rotation
			index = strfind(line, str_rot[2], true, index);
			if(index == -1) continue; // cannot find argument
			else index += 4 + 2;//CONST_STRLEN("=\""); /* =" */

			index = token_by_delim(line, var_from_line, '\"', index);
			if(index == -1) continue; // not a value

			rot[2] = floatstr(var_from_line);
		}

		switch(obj_type)
		{
			case LOADER_TYPE_MAP:
				LOADER_OBJECT(modelid, pos[0], pos[1], pos[2], rot[0], rot[1], rot[2]);
			case LOADER_TYPE_PCK:
				LOADER_PICKUP(modelid, 3/*!!!*/, pos[0], pos[1], pos[2], 0);
			case LOADER_TYPE_RAW:
			{
				new c[2] = { -1, -1 };
				#if defined LOADER_VEHICLE_RCOL
				LOADER_VEHICLE_RCOL(modelid, c[0], c[1]);
				#endif
				LOADER_VEHICLE(modelid, pos[0], pos[1], pos[2], rot[2], c[0], c[1], -1);
			}
			default: continue; // internal error
		}

		// counter
		objs_loaded++;
	}

	fclose(file_ptr);
	printf("Loaded %d objects from %s",objs_loaded,filename);
	return objs_loaded;
}



stock Load_Special_CLASS(const filename[],
	Float:dposx = 0.0, Float:dposy = 0.0, Float:dposz = 0.0, Float:dposa = 0.0,
	dweap1id = 0, dweap1ammo = 0,
	dweap2id = 0, dweap2ammo = 0,
	dweap3id = 0, dweap3ammo = 0,
	bool:silent = false)
{
	new File:file_ptr;
	new line[256];
	new var_from_line[64];

	new modelid;
	new Float:pos[4],
		weap[6];

	new index;
	new cls_loaded;

	file_ptr = fopen(filename,filemode:io_read);
	if(!file_ptr)
	{
		if(!silent) printf("Unable to read file %s", filename);
		return 0;
	}

	cls_loaded = 0;

	while(fread(file_ptr,line,sizeof(line)) > 0)
	{
		CHECK_LINE(line);

		index = token_by_delim(line,var_from_line,',', 0);
		if(index == (-1)) continue;
		modelid = strval(var_from_line);
		if(modelid < 1) continue;


		for(new i=0; i<4; i++)
		{
			index = token_by_delim(line,var_from_line,',',index+1);
			if(index == (-1)) break;

			if(strcmp(var_from_line, "def", true) == 0)
			{
				switch(i)
				{
					case 0: pos[0] = dposx;
					case 1: pos[1] = dposy;
					case 2: pos[2] = dposz;
					case 3: pos[3] = dposa;
				}
			}
			else pos[i] = floatstr(var_from_line);
		}
		if(index == -1) continue;

		for(new i=0; i<6; i++)
		{
			index = token_by_delim(line, var_from_line, (i == 5)?';':',',index+1);
			if(index == (-1)) break;

			if(strcmp(var_from_line, "def", true) == 0)
			{
				switch(i)
				{
					case 0: weap[0] = dweap1id;
					case 1: weap[1] = dweap1ammo;
					case 2: weap[2] = dweap2id;
					case 3: weap[3] = dweap2ammo;
					case 4: weap[4] = dweap3id;
					case 5: weap[5] = dweap3ammo;
				}
			}
			else
			{
				weap[i] = strval(var_from_line);
				if(weap[i] < 0) break;
			}
		}
		if(index == -1) continue;

		LOADER_CLASS(modelid, pos[0], pos[1], pos[2], pos[3],
			weap[0], weap[1],
			weap[2], weap[3],
			weap[4], weap[5]);

		cls_loaded++;
	}

	fclose(file_ptr);
	if(!silent) printf("Loaded %d classes from %s", cls_loaded,filename);
	return cls_loaded;
}

stock Load_Special_PICKUP(const filename[], pusharray[], size = sizeof pusharray,
	bool:silent = false)
{
	new File:file_ptr;
	new line[256];
	new var_from_line[64];

	new modelid,
		type;
	new Float:p[3];
	new vw;

	new index;
	new pcks_loaded;

	file_ptr = fopen(filename,filemode:io_read);
	if(!file_ptr)
	{
		if(!silent) printf("Unable to read file %s", filename);
		return 0;
	}

	pcks_loaded = 0;

	while(fread(file_ptr,line,sizeof(line)) > 0)
	{
		CHECK_LINE(line);

		index = 0;

		index = token_by_delim(line,var_from_line,',',index);
		if(index == (-1)) continue;
		modelid = strval(var_from_line);
		if(modelid < 1) continue;

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		type = strval(var_from_line);
		if(type < 0) continue;


		for(new i=0; i<3; i++)
		{
			index = token_by_delim(line,var_from_line,',',index+1);
			if(index == (-1))
				break;

			p[i] = floatstr(var_from_line);
		}
		if(index == -1) continue;

		index = token_by_delim(line,var_from_line,';',index+1);
		if(index == (-1))
			vw = 0;
		else
			vw = strval(var_from_line);

		if(pcks_loaded < size)
			pusharray[pcks_loaded] = LOADER_PICKUP(modelid, type, p[0], p[1], p[2], vw);
		else
			LOADER_PICKUP(modelid, type, p[0], p[1], p[2], vw);

		pcks_loaded++;
	}

	fclose(file_ptr);
	if(!silent) printf("Loaded %d/%d pickups from %s", pcks_loaded, size, filename);
	return pcks_loaded;
}

stock Load_Special_MAP(const filename[], pusharray[], size = sizeof pusharray,
	bool:silent = false)
{
	new File:file_ptr;
	new line[256];
	new var_from_line[64];

	//new modelname[64];
	//new interior;
	//new flags;

	new modelid;
	new Float:sx;
	new Float:sy;
	new Float:sz;
	new Float:rx;
	new Float:ry;
	new Float:rz;


	new index;
	new objs_loaded;

	file_ptr = fopen(filename,filemode:io_read);
	if(!file_ptr)
	{
		if(!silent) printf("Unable to read file %s", filename);
		return 0;
	}

	objs_loaded = 0;

	while(fread(file_ptr,line,sizeof(line)) > 0)
	{

		CHECK_LINE(line);

		index = 0;

		// model id
		index = token_by_delim(line,var_from_line,',',index);
		if(index == (-1)) continue;
		modelid = strval(var_from_line);
		if(modelid < 1) continue;

		// Read X, Y, Z, Rotation
		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		sx = floatstr(var_from_line);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		sy = floatstr(var_from_line);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		sz = floatstr(var_from_line);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		//if(var_from_line[0] == ' ')
		//	format(var_from_line, sizeof(var_from_line), "%s", var_from_line[1]);
		rx = floatstr(var_from_line[0]);

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
 		//if(var_from_line[0] == ' ')
		//	format(var_from_line, sizeof(var_from_line), "%s", var_from_line[1]);
 		ry = floatstr(var_from_line[0]);

		index = token_by_delim(line,var_from_line,';',index+1);
		if(index == (-1)) continue;
		//if(var_from_line[0] == ' ')
		//	format(var_from_line, sizeof(var_from_line), "%s", var_from_line[1]);
 		rz = floatstr(var_from_line);

		// create object
		#if defined IPL_DEBUG
		if(!silent) printf("CreateObject(%d, %f, %f, %f,%f, %f, %f); ", modelid, sx, sy, sz, rx, ry, rz);//, modelname, interior, flags);
		#endif

		new tmp = 0;

		#if defined objects_inc
		if(!IsValidObjectModel(modelid))
			if(!silent) printf("Warning(%d): bad object model (%d)", objs_loaded, modelid);
		#endif

		#if defined ENABLE_LOD_SUPPORT
		new lod = FindLODObject(modelid);

		#if defined objects_inc
		if(lod != modelid && !IsValidObjectModel(lod))
			if(!silent) printf("Warning(%d): bad  LOD object model (%d)", objs_loaded, lod);
		#endif


		if((tmp = LOADER_OBJECT(modelid, sx, sy, sz, rx, ry, rz, //FindLODModel("data/maps/list.lst", modelid));
			lod)) < 0)
		{
			if(!silent) printf("Error(%d): cannot load more objects", objs_loaded);
			return objs_loaded;
		}
		#else
		if((tmp = LOADER_OBJECT(modelid, sx, sy, sz, rx, ry, rz)) < 0)
		{
			if(!silent) printf("Error(%d): cannot load more objects", objs_loaded);
			return objs_loaded;
		}
		#endif

		if(objs_loaded < size)
			pusharray[objs_loaded] = tmp;

		objs_loaded++;
	}

	fclose(file_ptr);
	if(!silent) printf("Loaded %d/%d objects from %s", objs_loaded, size, filename);
	return objs_loaded;
}

stock Load_Special_ICON(const filename[], playerid, start_idx = 1,
	bool:silent = false)
{
	new File:file_ptr;
	new line[256];
	new var_from_line[64];

	new //id,
		type,
		color;
	new Float:pos[3];

	new index;
	new icos_loaded;

	file_ptr = fopen(filename,filemode:io_read);
	if(!file_ptr)
	{
		if(!silent) printf("Unable to read file %s", filename);
		return 0;
	}

	icos_loaded = 0;

	while(fread(file_ptr,line,sizeof(line)) > 0)
	{
		CHECK_LINE(line);

		/*
		index = token_by_delim(line,var_from_line,',', 0);
		if(index == (-1)) continue;
		id = strval(var_from_line);
		if(modelid < 0) continue;
		*/

		for(new i=0; i<3; i++)
		{
			index = token_by_delim(line,var_from_line,',',index+1);
			if(index == (-1))
				break;

			pos[i] = floatstr(var_from_line);
		}
		if(index == -1) continue;

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		type = strval(var_from_line);
		if(type < 0) continue;

		index = token_by_delim(line,var_from_line,',',index+1);
		if(index == (-1)) continue;
		color = strval(var_from_line);
		if(color < 0) continue;

		LOADER_ICON(playerid, start_idx + icos_loaded, pos[0], pos[1], pos[2], type, color);

		icos_loaded++;
	}

	fclose(file_ptr);
	if(!silent) printf("Loaded %d icons from %s", icos_loaded, filename);
	return icos_loaded;
}


/*
stock Load_VCOL(const filename[], dest[][])
{
	new File:file_ptr;
	new line[256];
	new var_from_line[64];

	new i;
	new modelid;


	new index;

	file_ptr = fopen(filename,filemode:io_read);
	CHECK_FILE(file_ptr)

	while(fread(file_ptr,line,sizeof(line)) > 0)
	{
		CHECK_LINE(line);

		index = 0;

		index = token_by_delim(line,var_from_line,':',index);
		if(index == (-1)) continue;
		modelid = strval(var_from_line) - 400;
		if(modelid < 0 || modelid > 212) continue;

		i = 0;
		while(index != -1)
		{
			index = token_by_delim(line,var_from_line,',',index+1);
			if(index == (-1)) break;
			dest[modelid][i] = strval(var_from_line);
			index = token_by_delim(line,var_from_line,',',index+1);
			if(index == (-1)) break;
			dest[modelid][i] |= strval(var_from_line) << 16;
			i++;
		}

	}

	fclose(file_ptr);

	return true;
}
*/